#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define FALSE 0
#define TRUE 1
#define MAX_BUFFER 2

/*********************************************************************************/
/*********************************************************************************/
/*********************************************************************************/

void print_help()
{
	printf("Usage:\n");
	printf("  tp0 -h\n");
	printf("  tp0 -V\n");
	printf("  tp0 [options] string1 string2\n");
	printf("  tp0 [options] string1\n");
	printf("Options:\n");
	printf("  -V, --version        Print version and quit.\n");
	printf("  -h, --help           Print this information and quit.\n");
	printf("  -d, --delete         Delete characters in string1\n");
	printf("  -s, --squeeze        Squeeze characters in input.\n\n");
	printf("Examples:\n");
	printf("  tp0 abc 123 < alpha.txt\n");
	printf("  tp0 -ds 123456789 aeiou\n");
}

void print_version()
{
	printf("Version 1.0\n");
}

/***
 * Este squeeze string lee el string_to_squeeze
 * busca los caracteres de la variable characters
 * y elimina las repeticiones.
 * Guarda en ret. (ret ya esta alocado).
 */
int squeeze_string(char* characters, char* string_to_squeeze, char* ret)
{
	unsigned int charact_size = strlen(string_to_squeeze), charact_pos = 0, ret_pos = 0;
	int found = FALSE;

	while(charact_pos < charact_size)
	{
		if(strchr(characters, string_to_squeeze[charact_pos]) != NULL)
		{
			if((!found) || (ret[ret_pos - 1] != string_to_squeeze[charact_pos]))
			{
				ret[ret_pos] = string_to_squeeze[charact_pos];
				++ret_pos;
				found = TRUE;
			}
		} else {
			ret[ret_pos] = string_to_squeeze[charact_pos];
			++ret_pos;
			found = FALSE;
		}
		++charact_pos;
	}

	ret[ret_pos] = '\0';

	return EXIT_SUCCESS;
}

/**
 * Extiende el ultimo caracter del string hasta n caracteres mas.
 */
char* extend_string(char* string, int n)
{
	int character = string[strlen(string)-1];

	memset(string+strlen(string),character,n);
	string[strlen(string)] = '\0';

	return string;
}

/**
 * Procesa stdin y realiza las operaciones de traduccion, eliminacion y/o squeeze
 * segun el valor de las variables.
 * Finalmente escribe sobre salida estandar.
 */
int tp0(int to_translate,int to_squeeze,int to_delete,char* first_string,char* second_string)
{
	FILE* input = stdin;
	FILE* error = stderr;
	FILE* output = stdout;

	char* buffer = (char*)malloc(MAX_BUFFER);
	int pos_buffer = 0;
	int qreallocs = 1;

	int character = fgetc(input);

	if (ferror (input)){
		fprintf(error, "Error reading stdin\n");
		return EXIT_FAILURE;
	}

	while(character != EOF && first_string)
	{
		/// Si ya supera el tamanio del buffer, hay que realocar.
		if (strlen(buffer)-1 < pos_buffer)
		{
			qreallocs++;
			char* new_buffer = (char*)realloc(buffer,MAX_BUFFER*qreallocs);

		    if (new_buffer != NULL)
		    {
		       buffer = new_buffer;
		    }
		    else
		    {
		       free (buffer);
		       fprintf(error,"Error (re)allocating memory");
		       return EXIT_FAILURE;
		    }
		}

		char* pos = strchr(first_string, character);

		if (pos != NULL)
		{
			if (to_translate)
			{
				// reemplaza por el valor de second string (el segundo argumento)
				buffer[pos_buffer] = second_string[pos - first_string];
				pos_buffer++;
			} else if (!to_delete) {
				buffer[pos_buffer] = character;
				pos_buffer++;
			}

		} else {
			buffer[pos_buffer] = character;
			pos_buffer++;
		}

		character = fgetc(input);

		if (ferror (input)){
			fprintf(error, "Error reading stdin\n");
			return EXIT_FAILURE;
		}
	}

	buffer[pos_buffer] = '\0';

	if (to_squeeze)
	{
		char* string_to_squeeze = (char*)malloc(pos_buffer);
		strncpy(string_to_squeeze, buffer, pos_buffer);

		if((to_delete) || (to_translate))
			squeeze_string(second_string, string_to_squeeze, buffer);
		else
			squeeze_string(first_string, string_to_squeeze, buffer);

		free(string_to_squeeze);
	}

	fputs(buffer,output);

	if (ferror (output)){
		fprintf(error, "Error writing stdout\n");
		return EXIT_FAILURE;
	}

	free(buffer);

	return EXIT_SUCCESS;
}

int main(int argc, char *argv[])
{
	char* first_string = NULL;
	char* second_string = NULL;

	int to_translate = FALSE;
	int to_squeeze = FALSE;
	int to_delete = FALSE;


	if (argc < 2)
	{
		fprintf(stderr, "Missing operand, for help use --help option.\n");
		exit(EXIT_FAILURE);
	}

	if ((strcmp(argv[1], "-d") == 0) || (strcmp(argv[1],"--delete") == 0))
	{
		if (argc > 3)
		{
			fprintf(stderr, "Extra operand: %s.\n", argv[3]);
			exit(EXIT_FAILURE);
		}

		to_delete = TRUE;
		first_string = argv[2];

	} else if ((strcmp(argv[1], "-s") == 0) || (strcmp(argv[1], "--squeeze") == 0)) {

		if (argc == 3)
		{
			to_squeeze = TRUE;
			first_string = argv[2];
		} else if (argc == 4)
		{
			to_translate = TRUE;
			to_squeeze = TRUE;

			first_string = argv[2];
			second_string = argv[3];
		} else {
			print_help();
			return EXIT_FAILURE;
		}

	} else if ((strcmp(argv[1], "-sd") == 0) || (strcmp(argv[1], "-ds") == 0))
	{
		to_delete = TRUE;
		to_squeeze = TRUE;

		first_string = argv[2];
		second_string = argv[3];

	} else if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0))
	{
		print_help();
		return EXIT_SUCCESS;
	} else if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0))
	{
		print_version();
		return EXIT_SUCCESS;
	} else
	{
		if (argc > 3)
		{
			fprintf(stderr, "Extra operand: %s.\n", argv[3]);
			exit(EXIT_FAILURE);
		}

		if (argc == 2)
		{
			if (argv[1][0] == '-')
			{
				fprintf(stderr,"tp0: opcion incorrecta -- '%s'\n",argv[1]);
			}
			else
			{
				fprintf(stderr,"tp0: falta un operando despues de <<%s>>\n",argv[1]);
			}
			exit(EXIT_FAILURE);
		}

		to_translate = TRUE;

		first_string = argv[1];
		second_string = argv[2];
	}

	if (to_translate && strlen(second_string) < strlen(first_string))
	{
		char* extended_string = (char*)malloc(strlen(first_string)+1);
		memcpy(extended_string,second_string,strlen(second_string));

		extend_string(extended_string, strlen(first_string) - strlen(second_string));
		tp0(to_translate, to_squeeze, to_delete, first_string, extended_string);

		free(extended_string);
	}
	else
	{
		tp0(to_translate, to_squeeze, to_delete, first_string, second_string);
	}

	return EXIT_SUCCESS;
}


